#include "imagedeal.h"
#include "opencv2/imgcodecs/legacy/constants_c.h"
#include "postprocess.h"
#include "string.h"
#include <bits/alltypes.h>

using namespace cv;
static const char *TAG = "[IMAGE DEAL]";
#define MAX_COUNT 10
std::string errMsg = "";

int g_channel = 0;
int g_width = 0;
int g_height = 0;
std::vector<std::string> g_labelData;
int g_isLoader = 0;

std::string InferenceResults = "";
std::string rtspUrl = "rtsp://example.com/stream";
VideoCapture capture;
// NCNN
ncnn::Net yolov8;

const char* class_names[] = {
        "Accordion", "Adhesive tape", "Aircraft", "Airplane", "Alarm clock", "Alpaca", "Ambulance", "Animal",
        "Ant", "Antelope", "Apple", "Armadillo", "Artichoke", "Auto part", "Axe", "Backpack", "Bagel",
        "Baked goods", "Balance beam", "Ball", "Balloon", "Banana", "Band-aid", "Banjo", "Barge", "Barrel",
        "Baseball bat", "Baseball glove", "Bat (Animal)", "Bathroom accessory", "Bathroom cabinet", "Bathtub",
        "Beaker", "Bear", "Bed", "Bee", "Beehive", "Beer", "Beetle", "Bell pepper", "Belt", "Bench", "Bicycle",
        "Bicycle helmet", "Bicycle wheel", "Bidet", "Billboard", "Billiard table", "Binoculars", "Bird",
        "Blender", "Blue jay", "Boat", "Bomb", "Book", "Bookcase", "Boot", "Bottle", "Bottle opener",
        "Bow and arrow", "Bowl", "Bowling equipment", "Box", "Boy", "Brassiere", "Bread", "Briefcase",
        "Broccoli", "Bronze sculpture", "Brown bear", "Building", "Bull", "Burrito", "Bus", "Bust", "Butterfly",
        "Cabbage", "Cabinetry", "Cake", "Cake stand", "Calculator", "Camel", "Camera", "Can opener", "Canary",
        "Candle", "Candy", "Cannon", "Canoe", "Cantaloupe", "Car", "Carnivore", "Carrot", "Cart", "Cassette deck",
        "Castle", "Cat", "Cat furniture", "Caterpillar", "Cattle", "Ceiling fan", "Cello", "Centipede",
        "Chainsaw", "Chair", "Cheese", "Cheetah", "Chest of drawers", "Chicken", "Chime", "Chisel", "Chopsticks",
        "Christmas tree", "Clock", "Closet", "Clothing", "Coat", "Cocktail", "Cocktail shaker", "Coconut",
        "Coffee", "Coffee cup", "Coffee table", "Coffeemaker", "Coin", "Common fig", "Common sunflower",
        "Computer keyboard", "Computer monitor", "Computer mouse", "Container", "Convenience store", "Cookie",
        "Cooking spray", "Corded phone", "Cosmetics", "Couch", "Countertop", "Cowboy hat", "Crab", "Cream",
        "Cricket ball", "Crocodile", "Croissant", "Crown", "Crutch", "Cucumber", "Cupboard", "Curtain",
        "Cutting board", "Dagger", "Dairy Product", "Deer", "Desk", "Dessert", "Diaper", "Dice", "Digital clock",
        "Dinosaur", "Dishwasher", "Dog", "Dog bed", "Doll", "Dolphin", "Door", "Door handle", "Doughnut",
        "Dragonfly", "Drawer", "Dress", "Drill (Tool)", "Drink", "Drinking straw", "Drum", "Duck", "Dumbbell",
        "Eagle", "Earrings", "Egg (Food)", "Elephant", "Envelope", "Eraser", "Face powder", "Facial tissue holder",
        "Falcon", "Fashion accessory", "Fast food", "Fax", "Fedora", "Filing cabinet", "Fire hydrant",
        "Fireplace", "Fish", "Flag", "Flashlight", "Flower", "Flowerpot", "Flute", "Flying disc", "Food",
        "Food processor", "Football", "Football helmet", "Footwear", "Fork", "Fountain", "Fox", "French fries",
        "French horn", "Frog", "Fruit", "Frying pan", "Furniture", "Garden Asparagus", "Gas stove", "Giraffe",
        "Girl", "Glasses", "Glove", "Goat", "Goggles", "Goldfish", "Golf ball", "Golf cart", "Gondola",
        "Goose", "Grape", "Grapefruit", "Grinder", "Guacamole", "Guitar", "Hair dryer", "Hair spray", "Hamburger",
        "Hammer", "Hamster", "Hand dryer", "Handbag", "Handgun", "Harbor seal", "Harmonica", "Harp",
        "Harpsichord", "Hat", "Headphones", "Heater", "Hedgehog", "Helicopter", "Helmet", "High heels",
        "Hiking equipment", "Hippopotamus", "Home appliance", "Honeycomb", "Horizontal bar", "Horse", "Hot dog",
        "House", "Houseplant", "Human arm", "Human beard", "Human body", "Human ear", "Human eye", "Human face",
        "Human foot", "Human hair", "Human hand", "Human head", "Human leg", "Human mouth", "Human nose",
        "Humidifier", "Ice cream", "Indoor rower", "Infant bed", "Insect", "Invertebrate", "Ipod", "Isopod",
        "Jacket", "Jacuzzi", "Jaguar (Animal)", "Jeans", "Jellyfish", "Jet ski", "Jug", "Juice", "Kangaroo",
        "Kettle", "Kitchen & dining room table", "Kitchen appliance", "Kitchen knife", "Kitchen utensil",
        "Kitchenware", "Kite", "Knife", "Koala", "Ladder", "Ladle", "Ladybug", "Lamp", "Land vehicle",
        "Lantern", "Laptop", "Lavender (Plant)", "Lemon", "Leopard", "Light bulb", "Light switch", "Lighthouse",
        "Lily", "Limousine", "Lion", "Lipstick", "Lizard", "Lobster", "Loveseat", "Luggage and bags", "Lynx",
        "Magpie", "Mammal", "Man", "Mango", "Maple", "Maracas", "Marine invertebrates", "Marine mammal",
        "Measuring cup", "Mechanical fan", "Medical equipment", "Microphone", "Microwave oven", "Milk",
        "Miniskirt", "Mirror", "Missile", "Mixer", "Mixing bowl", "Mobile phone", "Monkey", "Moths and butterflies",
        "Motorcycle", "Mouse", "Muffin", "Mug", "Mule", "Mushroom", "Musical instrument", "Musical keyboard",
        "Nail (Construction)", "Necklace", "Nightstand", "Oboe", "Office building", "Office supplies", "Orange",
        "Organ (Musical Instrument)", "Ostrich", "Otter", "Oven", "Owl", "Oyster", "Paddle", "Palm tree",
        "Pancake", "Panda", "Paper cutter", "Paper towel", "Parachute", "Parking meter", "Parrot", "Pasta",
        "Pastry", "Peach", "Pear", "Pen", "Pencil case", "Pencil sharpener", "Penguin", "Perfume", "Person",
        "Personal care", "Personal flotation device", "Piano", "Picnic basket", "Picture frame", "Pig",
        "Pillow", "Pineapple", "Pitcher (Container)", "Pizza", "Pizza cutter", "Plant", "Plastic bag", "Plate",
        "Platter", "Plumbing fixture", "Polar bear", "Pomegranate", "Popcorn", "Porch", "Porcupine", "Poster",
        "Potato", "Power plugs and sockets", "Pressure cooker", "Pretzel", "Printer", "Pumpkin", "Punching bag",
        "Rabbit", "Raccoon", "Racket", "Radish", "Ratchet (Device)", "Raven", "Rays and skates", "Red panda",
        "Refrigerator", "Remote control", "Reptile", "Rhinoceros", "Rifle", "Ring binder", "Rocket",
        "Roller skates", "Rose", "Rugby ball", "Ruler", "Salad", "Salt and pepper shakers", "Sandal",
        "Sandwich", "Saucer", "Saxophone", "Scale", "Scarf", "Scissors", "Scoreboard", "Scorpion",
        "Screwdriver", "Sculpture", "Sea lion", "Sea turtle", "Seafood", "Seahorse", "Seat belt", "Segway",
        "Serving tray", "Sewing machine", "Shark", "Sheep", "Shelf", "Shellfish", "Shirt", "Shorts",
        "Shotgun", "Shower", "Shrimp", "Sink", "Skateboard", "Ski", "Skirt", "Skull", "Skunk", "Skyscraper",
        "Slow cooker", "Snack", "Snail", "Snake", "Snowboard", "Snowman", "Snowmobile", "Snowplow",
        "Soap dispenser", "Sock", "Sofa bed", "Sombrero", "Sparrow", "Spatula", "Spice rack", "Spider",
        "Spoon", "Sports equipment", "Sports uniform", "Squash (Plant)", "Squid", "Squirrel", "Stairs",
        "Stapler", "Starfish", "Stationary bicycle", "Stethoscope", "Stool", "Stop sign", "Strawberry",
        "Street light", "Stretcher", "Studio couch", "Submarine", "Submarine sandwich", "Suit", "Suitcase",
        "Sun hat", "Sunglasses", "Surfboard", "Sushi", "Swan", "Swim cap", "Swimming pool", "Swimwear",
        "Sword", "Syringe", "Table", "Table tennis racket", "Tablet computer", "Tableware", "Taco", "Tank",
        "Tap", "Tart", "Taxi", "Tea", "Teapot", "Teddy bear", "Telephone", "Television", "Tennis ball",
        "Tennis racket", "Tent", "Tiara", "Tick", "Tie", "Tiger", "Tin can", "Tire", "Toaster", "Toilet",
        "Toilet paper", "Tomato", "Tool", "Toothbrush", "Torch", "Tortoise", "Towel", "Tower", "Toy",
        "Traffic light", "Traffic sign", "Train", "Training bench", "Treadmill", "Tree", "Tree house",
        "Tripod", "Trombone", "Trousers", "Truck", "Trumpet", "Turkey", "Turtle", "Umbrella", "Unicycle",
        "Van", "Vase", "Vegetable", "Vehicle", "Vehicle registration plate", "Violin", "Volleyball (Ball)",
        "Waffle", "Waffle iron", "Wall clock", "Wardrobe", "Washing machine", "Waste container", "Watch",
        "Watercraft", "Watermelon", "Weapon", "Whale", "Wheel", "Wheelchair", "Whisk", "Whiteboard", "Willow",
        "Window", "Window blind", "Wine", "Wine glass", "Wine rack", "Winter melon", "Wok", "Woman",
        "Wood-burning stove", "Woodpecker", "Worm", "Wrench", "Zebra", "Zucchini"
};

const char *class_names_coco[] = {
    "person",         "bicycle",    "car",           "motorcycle",    "airplane",     "bus",           "train",
    "truck",          "boat",       "traffic light", "fire hydrant",  "stop sign",    "parking meter", "bench",
    "bird",           "cat",        "dog",           "horse",         "sheep",        "cow",           "elephant",
    "bear",           "zebra",      "giraffe",       "backpack",      "umbrella",     "handbag",       "tie",
    "suitcase",       "frisbee",    "skis",          "snowboard",     "sports ball",  "kite",          "baseball bat",
    "baseball glove", "skateboard", "surfboard",     "tennis racket", "bottle",       "wine glass",    "cup",
    "fork",           "knife",      "spoon",         "bowl",          "banana",       "apple",         "sandwich",
    "orange",         "broccoli",   "carrot",        "hot dog",       "pizza",        "donut",         "cake",
    "chair",          "couch",      "potted plant",  "bed",           "dining table", "toilet",        "tv",
    "laptop",         "mouse",      "remote",        "keyboard",      "cell phone",   "microwave",     "oven",
    "toaster",        "sink",       "refrigerator",  "book",          "clock",        "vase",          "scissors",
    "teddy bear",     "hair drier", "toothbrush"};



// 获取输入参数
int GetAllInputParam(napi_env env, napi_callback_info info, Mat &img, std::vector<unsigned char> &model,
                     std::vector<std::string> &label, std::string &appPath) {
    // 设置输入参数个数
    size_t argc = 5;
    napi_value argv[5] = {nullptr};

    napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);

    size_t strSize;
    char strBuf[256];

    // 获取模型路径
    napi_get_value_string_utf8(env, argv[2], strBuf, sizeof(strBuf), &strSize);
    std::string modelPath(strBuf, strSize);
    OH_LOG_Print(LOG_APP, LOG_INFO, GLOBAL_RESMGR, TAG, "modelPath：%{public}s", modelPath.c_str());

    // 获取标签路径
    napi_get_value_string_utf8(env, argv[3], strBuf, sizeof(strBuf), &strSize);
    std::string labelPath(strBuf, strSize);
    OH_LOG_Print(LOG_APP, LOG_INFO, GLOBAL_RESMGR, TAG, "labelPath：%{public}s", labelPath.c_str());

    // 获取应用路径
    napi_get_value_string_utf8(env, argv[4], strBuf, sizeof(strBuf), &strSize);
    appPath.assign(strBuf, strSize);
    OH_LOG_Print(LOG_APP, LOG_INFO, GLOBAL_RESMGR, TAG, "appPath：%{public}s", appPath.c_str());


    void *imageData;
    size_t imageSize;
    napi_get_arraybuffer_info(env, argv[1], &imageData, &imageSize);

    std::vector<unsigned char> fileData{(uint8_t *)imageData, (uint8_t *)imageData + imageSize};
    img = imdecode(fileData, CV_LOAD_IMAGE_COLOR);
    if (img.empty()) {
        OH_LOG_Print(LOG_APP, LOG_INFO, GLOBAL_RESMGR, TAG, "img is empty");
        return -1;
    }

    if (!GetModelFromRawFile(env, argv[0], "", modelPath, model)) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, GLOBAL_RESMGR, TAG, "Get model data from rawfile failed!.");
        return -2;
    }

    if (!GetListFromRawFile(env, argv[0], "", labelPath, label)) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, GLOBAL_RESMGR, TAG, "Get label from rawfile failed!.");
        return -3;
    }

    return 0;
}

// 获取NCNN模型输入参数
int GetNcnnParam(napi_env env, napi_callback_info info, std::string &appPath) {
    size_t argc = 4;
    napi_value argv[4] = {nullptr};
    napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);

    size_t strSize;
    char strBuf[256];
    yolov8.opt.use_vulkan_compute = true;
    // 获取bin模型路径
    napi_get_value_string_utf8(env, argv[1], strBuf, sizeof(strBuf), &strSize);
    std::string modelBin(strBuf, strSize);
    OH_LOG_Print(LOG_APP, LOG_INFO, GLOBAL_RESMGR, TAG, "modelBin：%{public}s", modelBin.c_str());
    // 获取param模型路径
    napi_get_value_string_utf8(env, argv[2], strBuf, sizeof(strBuf), &strSize);
    std::string modelParam(strBuf, strSize);
    OH_LOG_Print(LOG_APP, LOG_INFO, GLOBAL_RESMGR, TAG, "modelParam：%{public}s", modelParam.c_str());

    // 获取应用路径
    napi_get_value_string_utf8(env, argv[3], strBuf, sizeof(strBuf), &strSize);
    appPath.assign(strBuf, strSize);
    OH_LOG_Print(LOG_APP, LOG_INFO, GLOBAL_RESMGR, TAG, "appPath：%{public}s", appPath.c_str());

    long model_b_size = GetNCNNSizeFromRawFile(env, argv[0], "", modelBin);
    if (model_b_size > 0) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, GLOBAL_RESMGR, TAG, "ModelBin size:%{public}ld", model_b_size);
    } else {
        OH_LOG_Print(LOG_APP, LOG_ERROR, GLOBAL_RESMGR, TAG, "Get model size from rawfile failed!");
        return -2;
    }
    long model_p_size = GetNCNNSizeFromRawFile(env, argv[0], "", modelParam);
    if (model_p_size > 0) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, GLOBAL_RESMGR, TAG, "ModelParam size:%{public}ld", model_p_size);
    } else {
        OH_LOG_Print(LOG_APP, LOG_ERROR, GLOBAL_RESMGR, TAG, "Get model size from rawfile failed!");
        return -2;
    }
    // 对应内存数据的获取
    unsigned char *model_b = new unsigned char[model_b_size];
    char *model_p = new char[model_p_size];
    if (!GetNCNNFromRawFile(env, argv[0], "", modelParam, (unsigned char *)model_p)) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, GLOBAL_RESMGR, TAG, "Get model data from rawfile failed!.");
        return -4;
    }
    if (model_p == nullptr) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, GLOBAL_RESMGR, TAG, "Error: Memory pointer is null");
        return -3;
    }
    int ret = yolov8.load_param_mem(model_p);
    OH_LOG_Print(LOG_APP, LOG_INFO, GLOBAL_RESMGR, TAG, "modelData address: %p", model_p);
    OH_LOG_Print(LOG_APP, LOG_ERROR, GLOBAL_RESMGR, TAG, "load modelParam %{public}d", ret);

    if (!GetNCNNFromRawFile(env, argv[0], "", modelBin, model_b)) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, GLOBAL_RESMGR, TAG, "Get model data from rawfile failed!.");
        return -2;
    }
    if (model_b == nullptr) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, GLOBAL_RESMGR, TAG, "Error: Memory pointer is null");
        return -3;
    }
    ret = yolov8.load_model(model_b);
    OH_LOG_Print(LOG_APP, LOG_INFO, GLOBAL_RESMGR, TAG, "modelData address: %p", model_b);
    OH_LOG_Print(LOG_APP, LOG_ERROR, GLOBAL_RESMGR, TAG, "load modelBIn %{public}d", ret);

    delete[] model_b;
    delete[] model_p;
    return 0;
}

// 获取模型输入参数
int GetModelParam(napi_env env, napi_callback_info info, std::vector<unsigned char> &model,
                  std::vector<std::string> &label, std::string &appPath) {
    // 设置输入参数个数
    size_t argc = 4;
    napi_value argv[4] = {nullptr};

    napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);

    size_t strSize;
    char strBuf[256];
    // 获取模型路径
    napi_get_value_string_utf8(env, argv[1], strBuf, sizeof(strBuf), &strSize);
    std::string modelPath(strBuf, strSize);
    OH_LOG_Print(LOG_APP, LOG_INFO, GLOBAL_RESMGR, TAG, "modelPath：%{public}s", modelPath.c_str());
    // 获取标签路径
    napi_get_value_string_utf8(env, argv[2], strBuf, sizeof(strBuf), &strSize);
    std::string labelPath(strBuf, strSize);
    OH_LOG_Print(LOG_APP, LOG_INFO, GLOBAL_RESMGR, TAG, "labelPath：%{public}s", labelPath.c_str());

    // 获取应用路径
    napi_get_value_string_utf8(env, argv[3], strBuf, sizeof(strBuf), &strSize);
    appPath.assign(strBuf, strSize);
    OH_LOG_Print(LOG_APP, LOG_INFO, GLOBAL_RESMGR, TAG, "appPath：%{public}s", appPath.c_str());

    if (!GetModelFromRawFile(env, argv[0], "", modelPath, model)) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, GLOBAL_RESMGR, TAG, "Get model data from rawfile failed!.");
        return -2;
    }

    if (!GetListFromRawFile(env, argv[0], "", labelPath, label)) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, GLOBAL_RESMGR, TAG, "Get label from rawfile failed!.");
        return -3;
    }

    return 0;
}

// 获取输入参数
int GetImageDateByRawfile(napi_env env, napi_callback_info info, Mat &img) {
    // 设置输入参数个数
    size_t argc = 2;
    napi_value argv[2] = {nullptr};

    napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);

    size_t strSize;
    char strBuf[256];
    // 获取图片路径
    napi_get_value_string_utf8(env, argv[1], strBuf, sizeof(strBuf), &strSize);
    std::string imagePath(strBuf, strSize);

    // 获取图片数据
    if (!GetMatFromRawFile(env, argv[0], "", imagePath, img)) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, GLOBAL_RESMGR, TAG, "Get Mat from rawfile failed!.");
        return -1;
    }
    return 0;
}

// 获取输入参数
int GetImageData(napi_env env, napi_callback_info info, Mat &img) {
    size_t argc = 1;
    napi_value argv[1] = {nullptr};
    napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
    void *imageData;
    size_t imageSize;
    napi_get_arraybuffer_info(env, argv[0], &imageData, &imageSize);
    std::vector<unsigned char> fileData{(uint8_t *)imageData, (uint8_t *)imageData + imageSize};
    img = imdecode(fileData, CV_LOAD_IMAGE_COLOR);
    if (img.empty()) {
        OH_LOG_Print(LOG_APP, LOG_INFO, GLOBAL_RESMGR, TAG, "image is empty!");
        return -1;
    }
    memset(imageData, 0, imageSize);
    imageSize = 0;
    return 0;
}

int GetImageDate(napi_env env, napi_callback_info info, Mat &img) {
    // 设置输入参数个数
    size_t argc = 1;
    napi_value argv[1] = {nullptr};

    napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);

    // 提取图片信息
    void *imageData;
    size_t imageSize;
    napi_get_arraybuffer_info(env, argv[0], &imageData, &imageSize);

    std::vector<unsigned char> fileData{(uint8_t *)imageData, (uint8_t *)imageData + imageSize};
    img = imdecode(fileData, CV_LOAD_IMAGE_COLOR);
    if (img.empty()) {
        OH_LOG_Print(LOG_APP, LOG_INFO, GLOBAL_RESMGR, TAG, "img is empty");
        return -1;
    }

    return 0;
}
int NCNN_ModelCreate(napi_env env, napi_callback_info info) {
    // 先获取输入参数
    if (g_isLoader == 1) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, GLOBAL_RESMGR, TAG, "模型已加载");
        return 0;
    }
    // 获取NCNN模型的路径以及创建导入两个模型并进行创建
    std::string appPath;
    int ret = GetNcnnParam(env, info, appPath);
    if (ret < 0) {
        errMsg = "获取输入参数失败";
        return -1;
    }
    OH_LOG_Print(LOG_APP, LOG_INFO, GLOBAL_RESMGR, TAG, "yolov8 model init success!");
    g_isLoader = 1;
    return 0;
}

int Rtsp_displayvideo(napi_env env, napi_callback_info info,cv::Mat &outMat){

    size_t argc = 1;
    int ret = 0;
    bool status = false;
    int fail_count = 0;
    napi_value argv[1] = {nullptr};
    napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
    napi_get_value_bool(env,argv[0],&status);
    capture.open(rtspUrl);
    if(!capture.isOpened()){
        OH_LOG_Print(LOG_APP, LOG_ERROR, GLOBAL_RESMGR, TAG, "can not to open rtsp video");
        return -1;
    }
    cv::Mat frame;
    cv::Mat bgr;
    while(capture.read(frame) && !status){
        if (frame.empty()) {
            OH_LOG_Print(LOG_APP, LOG_WARN, GLOBAL_RESMGR, TAG, "获取到空帧，跳过处理");
            continue;
        }
        bgr = frame.clone();
        ret = NcNN_ImageDeal_Rtsp(env,info,bgr,outMat);
        if(ret < 0){
            OH_LOG_Print(LOG_APP, LOG_ERROR, GLOBAL_RESMGR, TAG, "NCNN 模型处理出现问题,error=%{public}d",ret);
            fail_count++;
            if(fail_count >= MAX_COUNT){
                OH_LOG_Print(LOG_APP, LOG_ERROR, GLOBAL_RESMGR, TAG, "超过最大处理错误数，退出对应循环");
                break;
            }
            continue; //跳过一帧数据
        }else{
            fail_count = 0;
        }
        waitKey(30);
    }
    capture.release();
    return 0;
}
int Rtsp_Clear(napi_env env,napi_callback_info info)
{
    capture.release();
    
    return 0;
}

int NcNN_ImageDeal_Rtsp(napi_env env, napi_callback_info info,cv::Mat &srcMat ,cv::Mat &outMat) {
    if (g_isLoader == 0) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, GLOBAL_RESMGR, TAG, "模型未加载");
        return -1;
    }
    const int target_size = 640;
    const float prob_threshold = 0.27f;
    const float nms_threshold = 0.45f;
//    Mat srcImage;
//    int ret = GetImageData(env, info, srcImage);
//    if (ret < 0) {
//        errMsg = "获取输入参数失败";
//        return -1;
//    }
    OH_LOG_Print(LOG_APP, LOG_INFO, GLOBAL_RESMGR, TAG, "模型已加载成功，开始处理...");
    int image_w = srcMat.cols;
    int image_h = srcMat.rows;

    std::vector<int> strides(3);
    strides[0] = 8;
    strides[1] = 16;
    strides[2] = 32;
    const int max_stride = 32;
    // letterbox pad to multiple of max_stride
    int w = image_w;
    int h = image_h;
    float scale = 1.0f;

    if (w > h) {
        scale = (float)target_size / w;
        w = target_size;
        h = h * scale;
    } else {
        scale = (float)target_size / h;
        h = target_size;
        w = w * scale;
    }
    OH_LOG_Print(LOG_APP, LOG_INFO, GLOBAL_RESMGR, TAG, "开启yolov8n的后处理阶段!");
    ncnn::Mat in = ncnn::Mat::from_pixels_resize(srcMat.data, ncnn::Mat::PIXEL_BGR2RGB, image_w, image_h, w, h);
    // letterbox pad to target_size rectangle
    int wpad = (w + max_stride - 1) / max_stride * max_stride - w;
    int hpad = (h + max_stride - 1) / max_stride * max_stride - h;
    ncnn::Mat in_pad;
    ncnn::copy_make_border(in, in_pad, hpad / 2, hpad - hpad / 2, wpad / 2, wpad - wpad / 2, ncnn::BORDER_CONSTANT,
                           114.0f);

    const float norm_vals[3] = {1 / 255.f, 1 / 255.f, 1 / 255.f};
    in_pad.substract_mean_normalize(0, norm_vals);

    // 创建推理器ex
    ncnn::Extractor ex = yolov8.create_extractor();
    ex.input("in0", in_pad);
    ncnn::Mat out;
    ex.extract("out0", out);

    // 对应的提取后处理
    std::vector<_YOLO_OBJECT> proposals;
    generate_proposals(out, strides, in_pad, prob_threshold, proposals);
    qsort_descent_inplace(proposals);

    std::vector<int> picked;
    nms_sorted_bboxes(proposals, picked, nms_threshold, false);

    int count = picked.size();
    std::vector<_YOLO_OBJECT> objects;
    objects.resize(count);
    for (int i = 0; i < count; i++) {
        objects[i] = proposals[picked[i]];

        float x0 = (objects[i].rect.x - (wpad / 2)) / scale;
        float y0 = (objects[i].rect.y - (hpad / 2)) / scale;
        float x1 = (objects[i].rect.x + objects[i].rect.width - (wpad / 2)) / scale;
        float y1 = (objects[i].rect.y + objects[i].rect.height - (hpad / 2)) / scale;

        x0 = std::max(std::min(x0, (float)(image_w - 1)), 0.f);
        y0 = std::max(std::min(y0, (float)(image_h - 1)), 0.f);
        x1 = std::max(std::min(x1, (float)(image_w - 1)), 0.f);
        y1 = std::max(std::min(y1, (float)(image_h - 1)), 0.f);

        objects[i].rect.x = x0;
        objects[i].rect.y = y0;
        objects[i].rect.width = x1 - x0;
        objects[i].rect.height = y1 - y0;
    }

    char text[128];
    memset(text, 0, sizeof(text));
    // 绘制候选框
    OH_LOG_Print(LOG_APP, LOG_INFO, GLOBAL_RESMGR, TAG, "后处理完毕，开始绘制框图!");

    static cv::Scalar colors[] = {
        cv::Scalar(244, 67, 54),  cv::Scalar(233, 30, 99),   cv::Scalar(156, 39, 176), cv::Scalar(103, 58, 183),
        cv::Scalar(63, 81, 181),  cv::Scalar(33, 150, 243),  cv::Scalar(3, 169, 244),  cv::Scalar(0, 188, 212),
        cv::Scalar(0, 150, 136),  cv::Scalar(76, 175, 80),   cv::Scalar(139, 195, 74), cv::Scalar(205, 220, 57),
        cv::Scalar(255, 235, 59), cv::Scalar(255, 193, 7),   cv::Scalar(255, 152, 0),  cv::Scalar(255, 87, 34),
        cv::Scalar(121, 85, 72),  cv::Scalar(158, 158, 158), cv::Scalar(96, 125, 139)};

    cv::Mat image = srcMat.clone();
    for (size_t i = 0; i < objects.size(); i++) {
        const _YOLO_OBJECT &obj = objects[i];
        const cv::Scalar &color = colors[i % 19];
        OH_LOG_Print(LOG_APP, LOG_INFO, GLOBAL_RESMGR, TAG,
                     "%{public}d = %{public}.5f at %{public}.2f %{public}.2f %{public}.2f X %{public}.2f\n", obj.label,
                     obj.prob, obj.rect.x, obj.rect.y, obj.rect.width, obj.rect.height);
        cv::rectangle(image, obj.rect, color);
        char text[256];
        sprintf(text, "%s %.1f%%", class_names_coco[obj.label], obj.prob * 100);
        InferenceResults += text;
        int baseLine = 0;
        cv::Size label_size = cv::getTextSize(text, cv::FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine);
        int x = obj.rect.x;
        int y = obj.rect.y - label_size.height - baseLine;
        if (y < 0)
            y = 0;
        if (x + label_size.width > image.cols)
            x = image.cols - label_size.width;
        cv::rectangle(image, cv::Rect(cv::Point(x, y), cv::Size(label_size.width, label_size.height + baseLine)),
                      cv::Scalar(255, 255, 255), -1);

        cv::putText(image, text, cv::Point(x, y + label_size.height), cv::FONT_HERSHEY_SIMPLEX, 0.5,
                    cv::Scalar(0, 0, 0));
    }

    outMat = image;
    return 0;
}


int NcNN_ImageDeal(napi_env env, napi_callback_info info, cv::Mat &outMat) {
    if (g_isLoader == 0) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, GLOBAL_RESMGR, TAG, "模型未加载");
        return -1;
    }
    const int target_size = 640;
    const float prob_threshold = 0.27f;
    const float nms_threshold = 0.45f;
    Mat srcImage;
    int ret = GetImageData(env, info, srcImage);
    if (ret < 0) {
        errMsg = "获取输入参数失败";
        return -1;
    }
    OH_LOG_Print(LOG_APP, LOG_INFO, GLOBAL_RESMGR, TAG, "模型已加载成功，开始处理...");
    int image_w = srcImage.cols;
    int image_h = srcImage.rows;

    std::vector<int> strides(3);
    strides[0] = 8;
    strides[1] = 16;
    strides[2] = 32;
    const int max_stride = 32;
    // letterbox pad to multiple of max_stride
    int w = image_w;
    int h = image_h;
    float scale = 1.0f;

    if (w > h) {
        scale = (float)target_size / w;
        w = target_size;
        h = h * scale;
    } else {
        scale = (float)target_size / h;
        h = target_size;
        w = w * scale;
    }
    OH_LOG_Print(LOG_APP, LOG_INFO, GLOBAL_RESMGR, TAG, "开启yolov8n的后处理阶段!");
    ncnn::Mat in = ncnn::Mat::from_pixels_resize(srcImage.data, ncnn::Mat::PIXEL_BGR2RGB, image_w, image_h, w, h);
    // letterbox pad to target_size rectangle
    int wpad = (w + max_stride - 1) / max_stride * max_stride - w;
    int hpad = (h + max_stride - 1) / max_stride * max_stride - h;
    ncnn::Mat in_pad;
    ncnn::copy_make_border(in, in_pad, hpad / 2, hpad - hpad / 2, wpad / 2, wpad - wpad / 2, ncnn::BORDER_CONSTANT,
                           114.0f);

    const float norm_vals[3] = {1 / 255.f, 1 / 255.f, 1 / 255.f};
    in_pad.substract_mean_normalize(0, norm_vals);

    // 创建推理器ex
    ncnn::Extractor ex = yolov8.create_extractor();
    ex.input("in0", in_pad);
    ncnn::Mat out;
    ex.extract("out0", out);

    // 对应的提取后处理
    std::vector<_YOLO_OBJECT> proposals;
    generate_proposals(out, strides, in_pad, prob_threshold, proposals);
    qsort_descent_inplace(proposals);

    std::vector<int> picked;
    nms_sorted_bboxes(proposals, picked, nms_threshold, false);

    int count = picked.size();
    std::vector<_YOLO_OBJECT> objects;
    objects.resize(count);
    for (int i = 0; i < count; i++) {
        objects[i] = proposals[picked[i]];

        float x0 = (objects[i].rect.x - (wpad / 2)) / scale;
        float y0 = (objects[i].rect.y - (hpad / 2)) / scale;
        float x1 = (objects[i].rect.x + objects[i].rect.width - (wpad / 2)) / scale;
        float y1 = (objects[i].rect.y + objects[i].rect.height - (hpad / 2)) / scale;

        x0 = std::max(std::min(x0, (float)(image_w - 1)), 0.f);
        y0 = std::max(std::min(y0, (float)(image_h - 1)), 0.f);
        x1 = std::max(std::min(x1, (float)(image_w - 1)), 0.f);
        y1 = std::max(std::min(y1, (float)(image_h - 1)), 0.f);

        objects[i].rect.x = x0;
        objects[i].rect.y = y0;
        objects[i].rect.width = x1 - x0;
        objects[i].rect.height = y1 - y0;
    }

    char text[128];
    memset(text, 0, sizeof(text));
    // 绘制候选框
    OH_LOG_Print(LOG_APP, LOG_INFO, GLOBAL_RESMGR, TAG, "后处理完毕，开始绘制框图!");

    static cv::Scalar colors[] = {
        cv::Scalar(244, 67, 54),  cv::Scalar(233, 30, 99),   cv::Scalar(156, 39, 176), cv::Scalar(103, 58, 183),
        cv::Scalar(63, 81, 181),  cv::Scalar(33, 150, 243),  cv::Scalar(3, 169, 244),  cv::Scalar(0, 188, 212),
        cv::Scalar(0, 150, 136),  cv::Scalar(76, 175, 80),   cv::Scalar(139, 195, 74), cv::Scalar(205, 220, 57),
        cv::Scalar(255, 235, 59), cv::Scalar(255, 193, 7),   cv::Scalar(255, 152, 0),  cv::Scalar(255, 87, 34),
        cv::Scalar(121, 85, 72),  cv::Scalar(158, 158, 158), cv::Scalar(96, 125, 139)};

    cv::Mat image = srcImage.clone();
    for(size_t i = 0;i < objects.size();i++){
        const _YOLO_OBJECT& obj = objects[i];
        const cv::Scalar& color = colors[i % 19];
        OH_LOG_Print(LOG_APP, LOG_INFO, GLOBAL_RESMGR,TAG,"%{public}d = %{public}.5f at %{public}.2f %{public}.2f %{public}.2f X %{public}.2f\n"
                        ,obj.label,obj.prob,obj.rect.x,obj.rect.y,obj.rect.width,obj.rect.height);
        cv::rectangle(image,obj.rect,color);
        char text[256];
        sprintf(text, "%s %.1f%%", class_names_coco[obj.label], obj.prob * 100);
        InferenceResults += text;
        int baseLine = 0;
        cv::Size label_size = cv::getTextSize(text, cv::FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine);
        int x = obj.rect.x;
        int y = obj.rect.y - label_size.height - baseLine;
        if (y < 0)
            y = 0;
        if (x + label_size.width > image.cols)
            x = image.cols - label_size.width;
        cv::rectangle(image, cv::Rect(cv::Point(x, y), cv::Size(label_size.width, label_size.height + baseLine)),
                      cv::Scalar(255, 255, 255), -1);

        cv::putText(image, text, cv::Point(x, y + label_size.height),
                    cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 0, 0));
    }

    outMat = image;
    return 0;
}


std::string AI_ModelGetResults() 
{
    return InferenceResults;
}

void AI_ModelResultsClear()  { InferenceResults = ""; }

int AI_ModelDelete(napi_env env, napi_callback_info info) 
{
    if(g_isLoader == 0) {
        return 0;
    }
    g_isLoader = 0;

    yolov8.clear();
   
    return 0;
}

std::string AI_GetErrMsg()
{
    return errMsg;
}
